[网络流24题]太空飞行计划问题

2020-01-29
网络流24题

题意

有一些正权点和负权点,选择一个正权点就必须选择某些负权点,问最大收益

题解

说说怎么建图


来自 SSL_XXY_BlackCloud

如果求这个网络的最小割,那么要么S-正权点的边被割掉,要么和该正权点相连的负权点-T的边全部被割掉,这恰好符合题意

割掉的部分就是损失的部分,要不实验做不了,要不就是仪器要钱,用$\sum p$减去maxflow即可

输出方案的时候有trick,最后那次dfs中dep为0的实验就是被砍掉的,不做的;dep不为0的实验相连的仪器dep显然也不为0,又由T的dep为0可以推得它们连向T的边全部砍掉了

不能用e[i].f的理由就是e[i].f不能判断这个点是否被割掉,反例如下:

虽然1->3流完了,可是1->3并没有被割掉

调试记录

bfs没有重置dep

输出方案没想到用dep,在用e[i].f

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <cctype>
#include <cstring>
const int maxn = 505;
const int INF = 0x3f3f3f3f;
const int S = 0;
const int T = 500;
using namespace std;
struct E{
int to, nxt, f;
}e[maxn << 1]; int head[maxn], tot = 1;
void addedge(int u, int v, int f){
e[++tot].to = v, e[tot].nxt = head[u], e[tot].f = f;
head[u] = tot;
}
void ins(int u, int v, int f){addedge(u, v, f); addedge(v, u, 0);}
int n, m, c[maxn], p[maxn], tp;
int dep[maxn], last[maxn];
bool bfs(){
queue <int> q; while (!q.empty()) q.pop(); q.push(S);
memset(dep, 0, sizeof dep); dep[S] = 1;
while (!q.empty()){
int cur = q.front(); q.pop();
for (int i = head[cur]; i; i = e[i].nxt){
int v = e[i].to;
if (e[i].f > 0 && dep[v] <= 0){
dep[v] = dep[cur] + 1;
q.push(v);
}
}
}
return dep[T] != 0;
}
int dfs(int cur, int Max){
if (cur == T) return Max;
int flow = 0;
for (int i = head[cur]; i; i = e[i].nxt){
if (flow == Max) return flow;
int v = e[i].to;
if (dep[v] == dep[cur] + 1 && e[i].f > 0){
int tmp = dfs(v, min(Max - flow, e[i].f));
flow += tmp;
e[i].f -= tmp;
e[i ^ 1].f += tmp;
}
}
return flow;
}
int maxflow = 0;
void Dinic(){
while (bfs()) maxflow += dfs(S, INF);
} bool f;
inline int read(){
int x = 0; char ch = getchar();
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) x = x * 10 + (ch & 15), ch = getchar();
if (ch == '\n' || ch == '\r') f = 1;
return x;
}
int main(){
// freopen("1.in", "r", stdin);
scanf("%d%d", &n, &m);
for (int v, i = 1; i <= n; i++){
scanf("%d", p + i); tp += p[i]; f = 0;
while (v = read()){
ins(i, v + n, INF);
if (f == 1) break;
}
}
for (int i = 1; i <= m; i++) scanf("%d", c + i);
for (int i = 1; i <= n; i++) ins(S, i, p[i]);
for (int i = 1; i <= m; i++) ins(i + n, T, c[i]);
Dinic();
for (int i = 1; i <= n; i++) if (dep[i] > 0) printf("%d ", i); puts("");
for (int i = 1; i <= m; i++) if (dep[i + n] > 0) printf("%d ", i); puts("");
printf("%d\n", tp - maxflow);
return 0;
}